use std::fmt;

use lrlex::DefaultLexerTypes;
use lrpar::{NonStreamingLexer, Span};

#[derive(Debug)]
pub enum Block<'input> {
    Link { doc: &'input str, link: &'input str },
    Image { alt: &'input str, link: &'input str },
    Plaint { text: &'input str, span: Span },
    Decorater(Box<TextList<'input>>, Decorater),
    BR,
}
#[derive(Debug)]
pub enum Decorater {
    Bold,
    Italic,
    Underscore,
    DeleteLine,
}
impl Decorater {
    pub fn value(&self) -> i32 {
        match self {
            Decorater::Bold => 0,
            Decorater::Italic => 1,
            Decorater::Underscore => 2,
            Decorater::DeleteLine => 3,
        }
    }
}
impl<'input> fmt::Display for Block<'input> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Block::Link { doc, link } => {
                write!(f, "<a href=\"{link}\">{doc}</a>")
            }
            Block::Plaint { text, span: _ } => write!(f, "{}", text),
            Block::Decorater(block, decorater) => match decorater {
                Decorater::Bold => write!(f, "<b>{}</b>", block),
                Decorater::Italic => write!(f, "<i>{}</i>", block),
                Decorater::Underscore => write!(f, "<ins>{}</ins>", block),
                Decorater::DeleteLine => write!(f, "<s>{}</s>", block),
            },
            Block::BR => write!(f, "<br>"),
            Block::Image { alt, link } => {
                write!(f, "<img src=\"{link}\" alt=\"{alt}\"/>")
            }
        }
    }
}
#[derive(Debug)]
pub struct TextList<'input> {
    pub items: Vec<Block<'input>>,
}

impl<'input> fmt::Display for TextList<'input> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        for ele in self.iter() {
            write!(f, "{}", ele)?;
        }
        Ok(())
    }
}
impl<'input> TextList<'input> {
    pub fn new_by_empty_str() -> Self {
        TextList {
            items: vec![Block::Plaint {
                text: "",
                span: Span::new(0, 0),
            }],
        }
    }
    pub fn iter(&self) -> std::slice::Iter<Block<'input>> {
        self.items.iter()
    }
    pub fn append_line_break(&mut self) {
        self.items.push(Block::BR);
    }
    pub fn append_plaint<'lexer>(
        &mut self,
        s: &'input str,
        span_next: Span,
        lexer: &'lexer dyn NonStreamingLexer<'input, DefaultLexerTypes>,
    ) {
        if let Some(Block::Plaint { text: _, span }) = self.items.last() {
            if span.end() == span_next.start() {
                // println!("{:?}{:?}", span, span_next);
                let span = Span::new(span.start(), span_next.end());
                self.items.pop();
                self.items.push(Block::Plaint {
                    text: lexer.span_str(span),
                    span,
                });
                return;
            }
        }
        self.items.push(Block::Plaint {
            text: s,
            span: span_next,
        });
    }
    pub fn append<'lexer>(
        &mut self,
        next: TextList<'input>,
        lexer: &'lexer dyn NonStreamingLexer<'input, DefaultLexerTypes>,
    ) {
        if next.items.len() == 1 {
            if let Some(Block::Plaint { text, span }) = next.items.last() {
                if text.len() == span.len() && span.start() < span.end() {
                    // println!("{}:{}",text,span.len());
                    self.append_plaint(text, *span, lexer);
                    return;
                }
            }
        }
        self.append_list(next)
    }

    pub fn append_list(&mut self, mut next: TextList<'input>) {
        self.items.append(&mut next.items);
    }
}

pub fn generate_decorater<'lexer, 'input: 'lexer>(
    _lexer: &'lexer dyn NonStreamingLexer<'input, DefaultLexerTypes>,
    text: TextList<'input>,
    decorater: Decorater,
) -> TextList<'input> {
    let item = Block::Decorater(Box::new(text), decorater);
    TextList { items: vec![item] }
}
pub fn generate_plaint<'lexer, 'input: 'lexer>(
    lexer: &'lexer dyn NonStreamingLexer<'input, DefaultLexerTypes>,
    span: Span,
) -> (TextList<'input>, Span) {
    let text = lexer.span_str(span);
    let text = Block::Plaint { text, span };
    (TextList { items: vec![text] }, span)
}
pub fn generate_br<'input>() -> TextList<'input> {
    TextList {
        items: vec![Block::BR],
    }
}
pub fn generate_image<'lexer, 'input: 'lexer>(link: Block<'input>) -> Block<'input> {
    if let Block::Link { doc, link } = link {
        Block::Image { alt: doc, link }
    } else {
        panic!("生成图片信息时信息格式不断")
    }
}
pub fn generate_link<'lexer, 'input: 'lexer>(
    lexer: &'lexer dyn NonStreamingLexer<'input, DefaultLexerTypes>,
    doc: Span,
    link: Span,
) -> Block<'input> {
    Block::Link {
        doc: lexer.span_str(Span::new(doc.start() + 1, doc.end() - 1)),
        link: lexer.span_str(link).trim(),
    }
}
